#pragma once

#include <AVUIDependencyProperty.h>
#include <AVUIUncommonField.h>
#include <AVUIItemStructList.h>
#include <AVUIItemStructMap.h>

namespace AVUI {

class AnimationTimeline;
class DependencyObject;
class FrugalMap;
class AnimationClock;
class AnimationStorage;
typedef ItemStructList< TRefCountedPtr<AnimationClock> > AnimationClockList;

class AnimationLayer : public Object
{
public:
    AnimationLayer(AnimationStorage* pOwnerStorage);
    void ApplyAnimationClocks(AnimationClockList* pNewAnimationClocks, HandoffBehavior::Enum handoffBehavior, Object* pDefaultDestinationValue);
    TRefCountedPtr<Object> GetCurrentValue(Object* pDefaultDestinationValue);

private:

    void AppendAnimationClocks(AnimationClockList* pNewAnimationClocks);
    void DetachAnimationClocks();
    void OnCurrentStateInvalidated(Object* pSender, EventArgs* pArgs);
    void OnRemoveRequested(Object* pSender, EventArgs* pArgs);
    void SetAnimationClocks(AnimationClockList* pAnimationClocks);

    AnimationClockList m_animationClocks;
    bool m_hasStickySnapshotValue;
    TWeakPtr<AnimationStorage> m_pOwnerStorage;
    TRefCountedPtr<EventHandler> m_removeRequestedHandler;
    TRefCountedPtr<Object> m_pSnapshotValue;
};


class AnimationStorage : public Object
{
public:
    DECLARE_ELEMENT(AnimationStorage, Object);
    AnimationStorage();
    ~AnimationStorage();

    static void ApplyAnimationClock(DependencyObject* pDO, DependencyProperty* pDP, AnimationClock* pAnimationClock, HandoffBehavior::Enum handoffBehavior);
    static void ApplyAnimationClocks(DependencyObject* pDO, DependencyProperty* pDP, AnimationClockList* pAnimationClocks, HandoffBehavior::Enum handoffBehavior);
    static void ApplyAnimationClocksToLayer(DependencyObject* pDO, DependencyProperty* pDP, AnimationClockList* pAnimationClocks, HandoffBehavior::Enum handoffBehavior, long propertyTriggerLayerIndex);
    void AttachAnimationClock(AnimationClock* pAnimationClock, EventHandler* pRemoveRequestedHandler);
    static void BeginAnimation(DependencyObject* pDO, DependencyProperty* pDP, AnimationTimeline* pAnimation, HandoffBehavior::Enum handoffBehavior);
    void DetachAnimationClock(AnimationClock* pAnimationClock, EventHandler* pRemoveRequestedHandler);
    static TRefCountedPtr<AnimationStorage> EnsureStorage(DependencyObject* pDO, DependencyProperty* pDP);
    static FrugalMap* GetAnimatedPropertiesMap(DependencyObject* pDO);
    static TRefCountedPtr<Object> GetCurrentPropertyValue(AnimationStorage* pStorage, DependencyObject* pDO, DependencyProperty* pDP, PropertyMetadata* pMetadata, Object* pBaseValue);
    static AnimationStorage* GetStorage(DependencyObject* pDO, DependencyProperty* pDP);
    void Initialize(DependencyObject* pDO, DependencyProperty* pDP);
    static bool IsAnimationClockValid(DependencyProperty* pDP, AnimationClock* pAnimation);
    static bool IsAnimationValid(DependencyProperty* pDP, AnimationTimeline* pAnimation);
    static bool IsPropertyAnimatable(DependencyObject* pDO, DependencyProperty* pDP);
    void RemoveLayer(AnimationLayer* pLayer);
    void WritePostscript();

    bool get_IsEmpty();

private:

    void ClearAnimations();
    static TRefCountedPtr<AnimationStorage> CreateStorage(DependencyObject* pDO, DependencyProperty* pDP);
    void OnCurrentStateInvalidated(Object* pSender, EventArgs* pArgs);
    void OnCurrentTimeInvalidated(Object* pSender, EventArgs* pArgs);
    void OnRemoveRequested(Object* pSender, EventArgs* pArgs);

    AnimationClockList m_animationClocks;
    TRefCountedPtr<Object> m_pBaseValue;
    TRefCountedPtr<EventHandler> m_pCurrentTimeInvalidatedHandler;
    TWeakPtr<DependencyObject> m_pDependencyObject;
    DependencyProperty* m_pDependencyProperty;
    bool m_hasStickySnapshotValue;
    ItemStructMap< TRefCountedPtr<AnimationLayer> > m_propertyTriggerLayers;
    TRefCountedPtr<EventHandler> m_pRemoveRequestedHandler;
    TRefCountedPtr<Object> m_pSnapshotValue;

    static UncommonField<FrugalMap> AnimatedPropertyMapField;
};


}; // namespace AVUI
